package com.tools.middle.elasticsearch;

import com.tools.common.exception.DataGenerationException;
import com.tools.common.object.BasicEnum;
import com.tools.common.object.Note;
import org.apache.http.HttpHost;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * ElasticSearch 客户端配置项包装类
 * */
@Note("ElasticSearch 客户端配置项包装类")
public class ESSource {

    @Note("ElasticSearch 的主机节点数组")
    private HttpHost[] nodes;

    @Note("ElasticSearch 的用户名")
    private String username;

    @Note("ElasticSearch 的密码")
    private String password;

    @Note("连接 ElasticSearch 服务端的超时时间。单位毫秒")
    private long connectTimeout = 1000;

    @Note("请求超时时间。单位毫秒")
    private long requestTimeout = 500;

    @Note("Socket 连接超时时间。单位毫秒")
    private long socketTimeout = 3000;

    @Note("最大连接数")
    private int maxConnectTotal = 100;

    @Note("最大连接路由线路")
    private int maxConnectPreRoute = 100;

    public ESSource() {}

    public static ESSource of() {
        return new ESSource();
    }

    @Note("读取 properties 里的配置项，转为实例返回")
    public static ESSource from(Map properties) {
        ESSource source = new ESSource();
        if(properties == null || properties.isEmpty()) return source;
        source.setUsername((String) properties.get("elasticsearch-username"));
        source.setPassword((String) properties.get("elasticsearch-password"));
        Object esConnectionRequestTimeout = properties.get("elasticsearch-connection-request-timeout");
        source.setRequestTimeout(BasicEnum.longValue(esConnectionRequestTimeout));
        Object esConnectTimout = properties.get("elasticsearch-connect-timeout");
        source.setConnectTimeout(BasicEnum.longValue(esConnectTimout));
        Object esSocketTimeout = properties.get("elasticsearch-socket-timeout");
        source.setSocketTimeout(BasicEnum.longValue(esSocketTimeout));
        source.setMaxConnectTotal((Integer) properties.get("elasticsearch-max-conn-total"));
        source.setMaxConnectPreRoute((Integer) properties.get("elasticsearch-max-conn-per-route"));
        String hosts = (String) properties.get("elasticsearch-nodes");
        if(hosts == null || hosts.isEmpty()) {
            throw new DataGenerationException("没有扫描到 ElasticSearch 节点，请至少配置一个以上的 ElasticSearch 节点：【节点ip:节点端口】。" +
                    "多个节点用,分隔：【ip1:端口1,ip2:端口2……】 注意,前后不要有其他字符");
        }
        String[] a = hosts.split(",");
        int length = a.length;
        //单机
        if(length < 2) {
            HttpHost hostNode = ESKit.newHostNode(a[0]);
            source.setNodes(new HttpHost[] {hostNode});
            return source;
        }
        //集群
        HttpHost[] httpHosts = new HttpHost[length];
        for (int i = 0; i < length; i++) {
            httpHosts[i] = ESKit.newHostNode(a[i]);
        }
        source.setNodes(httpHosts);
        return source;
    }

    /* *******************************************************************************************
     *
     *      Getter / Setter
     *
     * *******************************************************************************************
     * */

    public HttpHost[] getNodes() {
        if(nodes == null || nodes.length == 0) throw new NullPointerException("ElasticSearch 的主机节点为空");
        return nodes;
    }

    public void setNodes(HttpHost[] nodes) {
        if(nodes == null || nodes.length == 0) throw new NullPointerException("ElasticSearch 的主机节点为空");
        this.nodes = nodes;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public long getRequestTimeout() {
        return requestTimeout;
    }

    public void setRequestTimeout(Long requestTimeout) {
        this.requestTimeout = (requestTimeout == null || requestTimeout < 0) ? this.requestTimeout : requestTimeout;
    }

    public long getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(Long connectTimeout) {
        this.connectTimeout = (connectTimeout == null || connectTimeout < 0) ? this.connectTimeout : connectTimeout;
    }

    public long getSocketTimeout() {
        return socketTimeout;
    }

    public void setSocketTimeout(Long socketTimeout) {
        this.socketTimeout = (socketTimeout == null || socketTimeout < 0) ? this.socketTimeout : socketTimeout;
    }

    public int getMaxConnectTotal() {
        return maxConnectTotal;
    }

    public void setMaxConnectTotal(Integer maxConnectTotal) {
        this.maxConnectTotal = (maxConnectTotal == null || maxConnectTotal < 0) ? this.maxConnectTotal : maxConnectTotal;
    }

    public int getMaxConnectPreRoute() {
        return maxConnectPreRoute;
    }

    public void setMaxConnectPreRoute(Integer maxConnectPreRoute) {
        this.maxConnectPreRoute = (maxConnectPreRoute == null || maxConnectPreRoute < 0) ? this.maxConnectPreRoute : maxConnectPreRoute;
    }

    @Override
    public String toString() {
        return "ESSource{" +
                "nodes=" + Arrays.toString(nodes) +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", connectTimeout=" + connectTimeout +
                ", requestTimeout=" + requestTimeout +
                ", socketTimeout=" + socketTimeout +
                ", maxConnectTotal=" + maxConnectTotal +
                ", maxConnectPreRoute=" + maxConnectPreRoute +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ESSource esSource = (ESSource) o;
        return connectTimeout == esSource.connectTimeout && requestTimeout == esSource.requestTimeout && socketTimeout == esSource.socketTimeout && maxConnectTotal == esSource.maxConnectTotal && maxConnectPreRoute == esSource.maxConnectPreRoute && Arrays.equals(nodes, esSource.nodes) && Objects.equals(username, esSource.username) && Objects.equals(password, esSource.password);
    }

    @Override
    public int hashCode() {
        int result = Objects.hash(username, password, connectTimeout, requestTimeout, socketTimeout, maxConnectTotal, maxConnectPreRoute);
        result = 31 * result + Arrays.hashCode(nodes);
        return result;
    }
}
